#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os
import sqlite3
import uuid

from pydantic import BaseModel, Field

from exchange.commons.common import escape_sqlite_character


class ExchangeSqliteService:
    @staticmethod
    def write_metadata_to_sqlite_file(path, data_params, force_insert_data=False):
        sqlite_path = os.path.join(path, "sqlite")
        if not os.path.exists(sqlite_path):
            os.makedirs(sqlite_path)
        ExchangeSqliteService.init_db(sqlite_path, data_params, force_insert_data)

    @staticmethod
    def write_metadata_list_to_sqlite_file(path, data_params: list, force_insert_data=False):
        sqlite_path = os.path.join(path, "sqlite")
        if not os.path.exists(sqlite_path):
            os.makedirs(sqlite_path)
        sqlite_db_name = "copymetadata.sqlite"
        db_path = os.path.join(sqlite_path, sqlite_db_name)
        conn = sqlite3.connect(db_path)

        t_copy_metadata = "T_COPY_METADATA"
        create_sql_table = ExchangeSqliteService.create_table_struct(t_copy_metadata)
        conn.execute(create_sql_table)
        conn.commit()

        # 数据库信息是否已经存在，用NAME+TYPE字段过滤，不存在则插入数据库结构信息
        statement = f"INSERT INTO {t_copy_metadata} VALUES(?,?,?,?,?,?,?,?,?,?,?)"
        sql_list = []
        if force_insert_data:
            for data_param in data_params:
                sql_list.extend(ExchangeSqliteService.init_sql_params(conn, data_param, t_copy_metadata))
        else:
            for data_param in data_params:
                if not ExchangeSqliteService.is_exist_sql(conn, t_copy_metadata, data_param):
                    sql_list.extend(ExchangeSqliteService.init_sql_params(conn, data_param, t_copy_metadata))
        if len(sql_list) > 0:
            conn.executemany(statement, sql_list)
            conn.commit()
        conn.close()

    @staticmethod
    def init_db(path, data_params, force_insert_data):
        sqlite_db_name = "copymetadata.sqlite"
        db_path = os.path.join(path, sqlite_db_name)
        conn = sqlite3.connect(db_path)

        t_copy_metadata = "T_COPY_METADATA"
        create_sql_table = ExchangeSqliteService.create_table_struct(t_copy_metadata)
        conn.execute(create_sql_table)
        conn.commit()

        # 数据库信息是否已经存在，用NAME+TYPE字段过滤，不存在则插入数据库结构信息
        statement = f"INSERT INTO {t_copy_metadata} VALUES(?,?,?,?,?,?,?,?,?,?,?)"
        if data_params is not None:
            need_insert_data = force_insert_data or (
                not ExchangeSqliteService.is_exist_sql(conn, t_copy_metadata, data_params))
            if need_insert_data:
                database_data = ExchangeSqliteService.init_sql_params(conn, data_params, t_copy_metadata)
                conn.executemany(statement, database_data)
                conn.commit()
        conn.close()

    @staticmethod
    def is_exist_sql(conn, table_name, data_params):
        data_name = escape_sqlite_character(data_params.data_name)
        data_parent_path = escape_sqlite_character(data_params.data_parent_path)
        exist_statement = f"SELECT count(*) from '{table_name}' where \
            NAME = '{data_name}' and TYPE = '{data_params.data_type}' \
            and PARENT_PATH = '{data_parent_path}'"
        exist_cursor = conn.execute(exist_statement)
        conn.commit()
        exist_database_count = exist_cursor.fetchall()
        return len(exist_database_count) != 0 and exist_database_count[0][0] != 0

    @staticmethod
    def create_table_struct(t_copy_metadata):
        return f'''CREATE TABLE IF NOT EXISTS '{t_copy_metadata}'(
            UUID varchar(512) PRIMARY KEY NOT NULL,
            NAME TEXT NOT NULL,
            TYPE varchar(32) NOT NULL,
            PARENT_PATH TEXT NOT NULL,
            PARENT_UUID varchar(512) NOT NULL,
            SIZE BIGINT,
            CREATE_TIME varchar(64),
            MODIFY_TIME varchar(64),
            EXTEND_INFO TEXT,
            RES_TYPE varchar (64),
            RES_SUB_TYPE varchar (64));'''

    @staticmethod
    def init_sql_params(conn, data_params, table_name):
        sqlite_table_param = SqliteTable()

        parent_guid = ExchangeSqliteService.get_parent_guid(conn, data_params, table_name)

        return [(str(uuid.uuid1()), data_params.data_name, data_params.data_type, data_params.data_parent_path,
                 parent_guid, data_params.data_size, data_params.create_time,
                 data_params.modify_time, data_params.extend_info, sqlite_table_param.res_type,
                 sqlite_table_param.res_sub_type)]

    @staticmethod
    def get_parent_guid(conn, data_params, table_name):
        data_parent_path = escape_sqlite_character(data_params.data_parent_path)
        get_statement = f"SELECT UUID from '{table_name}' \
            WHERE PARENT_PATH || '/' || NAME == '{data_parent_path}'"
        get_cursor = conn.execute(get_statement)
        conn.commit()
        fit_items = get_cursor.fetchall()
        if len(fit_items) != 0 and fit_items[0][0] != 0:
            return fit_items[0][0]
        else:
            return 0


class SqliteTable(BaseModel):
    uuid: str = Field(None, description='UUID')
    name: str = Field(None, description='name')
    type: str = Field(None, description='type')
    parent_path: str = Field(default='/', description='父节点路径')
    parent_uuid: str = Field(None, description='PARENT_UUID')
    size: str = Field(None, description='大小')
    create_time: str = Field(None, description='创建时间')
    modify_time: str = Field(None, description='修改时间')
    extend_info: str = Field(None, description='扩展信息')
    res_type: str = Field(None, description='RES_TYPE')
    res_sub_type: str = Field(None, description='RES_SUB_TYPE')


class SqliteInputParam(BaseModel):
    data_name: str = Field(None, description='name')
    data_type: str = Field(None, description='type')
    data_parent_path: str = Field(None, description='父节点路径')
    create_time: str = Field(None, description='创建时间')
    modify_time: str = Field(None, description='修改时间')
    data_size: str = Field(None, description='大小')
    extend_info: str = Field(None, description='扩展信息')
